#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/limits.h>
#include <linux/string.h>
#include <linux/file.h>
#include <linux/fs.h>
#include <linux/net.h>
#include <net/sock.h>
#include <target/target_core_base.h>
#if defined(TK4) || defined(TK4_NEW)
#include <linux/genhd.h>
#else
#include <linux/blkdev.h>
#endif
#include <linux/pagemap.h>
#include "kprobe_prehook.h"
#include "syms.h"
#include "./include/kernel/sched/sched.h"
#include "./include/drivers/target/target_core_file.h"
#include "./include/drivers/block/loop.h"

#define shm_file_data(file) (*((struct shm_file_data **)&(file)->private_data))
extern unsigned int sysctl_module_debug;
struct shm_file_data {
    int id;
    struct ipc_namespace *ns;
    struct file *file;
    const struct vm_operations_struct *vm_ops;
};
bool print_func_name(void *opt, void *opt2, void *opt3, char *pointer, char *func)
{
	bool ret = true;

	if (sysctl_module_debug != 2)
		return false;

	/***************** fs *****************/
	if ((check_func_name("vfs_read") || check_func_name("new_sync_read")) && strstr(pointer, "file->f_op->read_iter")) {
		struct file *file = (struct file *)opt;
		sprintf(func, FUNCTION_PRINT_FORMAT, file->f_op->read_iter);
		return ret;
	}
	if ((check_func_name("vfs_write") || check_func_name("new_sync_write")) && strstr(pointer, "file->f_op->write_iter")) {
		struct file *file = (struct file *)opt;
		sprintf(func, FUNCTION_PRINT_FORMAT, file->f_op->write_iter);
		return ret;
	}
	if (check_func_name("vfs_read") && strstr(pointer, "file->f_op->read")) {
		struct file *file = (struct file *)opt;
		sprintf(func, FUNCTION_PRINT_FORMAT, file->f_op->read);
		return ret;
	}
	if (check_func_name("vfs_write") && strstr(pointer, "file->f_op->write")) {
		struct file *file = (struct file *)opt;
		sprintf(func, FUNCTION_PRINT_FORMAT, file->f_op->write);
		return ret;
	}
	if (check_func_name("vfs_ioctl") && strstr(pointer, "filp->f_op->unlocked_ioctl")) {
		struct file *file = (struct file *)opt;
		sprintf(func, FUNCTION_PRINT_FORMAT, file->f_op->unlocked_ioctl);
		return ret;
	}
	if (check_func_name("compat_blkdev_ioctl") && strstr(pointer, "disk->fops->compat_ioctl")) {
		struct file *file = (struct file *)opt;
		struct inode *inode = file->f_mapping->host;
#if defined(TK4) || defined(TK4_NEW)
		struct block_device *bdev = inode->i_bdev;
#else
		struct block_device *bdev = I_BDEV(file->f_mapping->host);
#endif
		struct gendisk *disk = bdev->bd_disk;
		sprintf(func, FUNCTION_PRINT_FORMAT, disk->fops->compat_ioctl);
		return ret;
	}
	if (check_func_name("call_mmap") && strstr(pointer, "file->f_op->mmap")) {
		struct file *file = (struct file *)opt;
		sprintf(func, FUNCTION_PRINT_FORMAT, file->f_op->mmap);
		return ret;
	}
	if (check_func_name("vfs_fsync_range") && strstr(pointer, "file->f_op->fsync")) {
		struct file *file = (struct file *)opt;
		sprintf(func, FUNCTION_PRINT_FORMAT, file->f_op->fsync);
		return ret;
	}
	if ((check_func_name("do_splice_to")) && strstr(pointer, "splice_read")) {
		struct file *in = (struct file *)opt;
		if (in->f_op->splice_read)
			sprintf(func, FUNCTION_PRINT_FORMAT, in->f_op->splice_read);
		else
			sprintf(func, "%s", "default_file_splice_read");
		return ret;
	}
	if ((check_func_name("do_splice_from")) && strstr(pointer, "splice_write")) {
		struct file *out = (struct file *)opt;
		if (out->f_op->splice_write)
			sprintf(func, FUNCTION_PRINT_FORMAT, out->f_op->splice_write);
		else
			sprintf(func, "%s", "default_file_splice_write");
		return ret;
	}
	if (check_func_name("get_unmapped_area") && strstr(pointer, "file->f_op->fsync")) {
		struct file *file = (struct file *)opt;
		sprintf(func, FUNCTION_PRINT_FORMAT, file->f_op->fsync);
		return ret;
	}
	if (strstr(pointer, "file->f_op->fallocate")) {
		struct loop_device *lo = NULL;
		struct se_cmd *cmd = NULL;
		struct fd_dev *fd_dev = NULL;
		struct file *file = NULL;
		if (check_func_name("lo_fallocate"))
			lo = (struct loop_device *)opt;
			file = lo->lo_backing_file;
		if (check_func_name("fd_execute_unmap")) {
			cmd = (struct se_cmd *)opt;
			fd_dev = container_of(cmd->se_dev, struct fd_dev, dev);
			file = fd_dev->fd_file;
		}
		if (check_func_name("vfs_fallocate"))
			file = (struct file *)opt;
		if (file)
			sprintf(func, FUNCTION_PRINT_FORMAT, file->f_op->fallocate);
		return ret;
	}
	if (check_func_name("sfd->file->f_op->fallocate") && (strstr(pointer, "std->file->i_op->fallocate"))) {
		struct file *file = NULL;
		struct shm_file_data *sfd;
		file = (struct file *)opt;
		sfd = shm_file_data(file);
		if (sfd->file->f_op->fallocate)
			sprintf(func, FUNCTION_PRINT_FORMAT, sfd->file->f_op->fallocate);
		return ret;
	}
	if (check_func_name("ioctl_fiemap") && (strstr(pointer, "inode->i_op->fiemap"))) {
		struct inode *inode;
		struct file *filp = (struct file *)opt;
		inode = file_inode(filp);
		if (inode->i_op->fiemap)
			sprintf(func, FUNCTION_PRINT_FORMAT, inode->i_op->fiemap);
		return ret;
	}
#if 0
	if (check_func_name("ovl_fiemap") && (strstr(pointer, "realinode->i_op->fiemap"))) {
		struct inode *inode = (struct inode *)opt;
		struct inode *realinode = ovl_inode_real(inode);
		if (realinode->i_op->fiemap)
			sprintf(func, FUNCTION_PRINT_FORMAT, realinode->i_op->fiemap);
		return;
	}
#endif
	sub_print_func_name(opt, opt2, opt3, pointer, func);
	if (strstr(pointer, "mapping->a_ops->writepages")) {
		struct address_space *mapping = (struct address_space *)opt;
		if (mapping->a_ops->writepages)
			sprintf(func, FUNCTION_PRINT_FORMAT, mapping->a_ops->writepages);
		return ret;
	}
	if ((check_func_name("pagecache_write_begin")) && strstr(pointer, "a_ops->write_begin")) {
		struct address_space *mapping = (struct address_space *)opt2;
		if (mapping && mapping->a_ops->write_begin)
			sprintf(func, FUNCTION_PRINT_FORMAT, mapping->a_ops->write_begin);
		return ret;
	}
	if ((check_func_name("generic_perform_write")) && strstr(pointer, "a_ops->write_begin")) {
		struct file *file = (struct file *)opt;
		struct address_space *mapping = file->f_mapping;
		if (mapping && mapping->a_ops->write_begin)
			sprintf(func, FUNCTION_PRINT_FORMAT, mapping->a_ops->write_begin);
		return ret;
	}
	if ((check_func_name("pagecache_write_end")) && strstr(pointer, "a_ops->write_end")) {
		struct address_space *mapping = (struct address_space *)opt2;
		if (mapping && mapping->a_ops->write_end)
			sprintf(func, FUNCTION_PRINT_FORMAT, mapping->a_ops->write_end);
		return ret;
	}
	if ((check_func_name("generic_perform_write")) && strstr(pointer, "a_ops->write_end")) {
		struct file *file = (struct file *)opt;
		struct address_space *mapping = file->f_mapping;
		if (mapping && mapping->a_ops->write_end)
			sprintf(func, FUNCTION_PRINT_FORMAT, mapping->a_ops->write_end);
		return ret;
	}
#if 0
	if (strstr(pointer, "mapping->a_ops->set_page_dirty")) {
		struct page *page = (struct page *)opt;
		struct swap_info_struct *sis = page_swap_info(page);
		struct address_space *mapping = NULL;

		if (sis && sis->swap_file)
			mapping = sis->swap_file->f_mapping;
		if (mapping && mapping->a_ops->writepages)
			sprintf(func, FUNCTION_PRINT_FORMAT, mapping->a_ops->set_page_dirty);
		return;
	}
#endif
	if ((check_func_name("bmap")) && strstr(pointer, "inode->i_mapping->a_ops->bmap")) {
		struct inode *inode = (struct inode *)opt;
		if (inode->i_mapping->a_ops->bmap)
			sprintf(func, FUNCTION_PRINT_FORMAT, inode->i_mapping->a_ops->bmap);
		return ret;
	}
	if ((check_func_name("ioctl_fibmap")) && strstr(pointer, "mapping->a_ops->bmap")) {
		struct file *filp = (struct file *)opt;
		struct address_space *mapping = filp->f_mapping;
		if (mapping->a_ops->bmap)
			sprintf(func, FUNCTION_PRINT_FORMAT, mapping->a_ops->bmap);
		return ret;
	}
	if ((check_func_name("ioctl_fibmap")) && strstr(pointer, "mapping->a_ops->bmap")) {
		struct file *filp = (struct file *)opt;
		struct address_space *mapping = filp->f_mapping;
		if (mapping->a_ops->bmap)
			sprintf(func, FUNCTION_PRINT_FORMAT, mapping->a_ops->bmap);
		return ret;
	}
	if ((check_func_name("page_seek_hole_data")) && strstr(pointer, "ops->is_partially_uptodate")) {
		struct inode *inode = (struct inode *)opt;
		if (inode->i_mapping->a_ops->is_partially_uptodate)
			sprintf(func, FUNCTION_PRINT_FORMAT, inode->i_mapping->a_ops->is_partially_uptodate);
		return ret;
	}
	if ((check_func_name("do_writepages")) && strstr(pointer, "mapping->a_ops->writepages")) {
		struct address_space *mapping = (struct address_space *)opt;
		if (mapping->a_ops->writepages)
			sprintf(func, FUNCTION_PRINT_FORMAT, mapping->a_ops->writepages);
		return ret;
	}
	if ((check_func_name("pageout")) && strstr(pointer, "mapping->a_ops->writepage")) {
		struct address_space *mapping = (struct address_space *)opt2;
		if (mapping->a_ops->writepage)
			sprintf(func, FUNCTION_PRINT_FORMAT, mapping->a_ops->writepage);
		return ret;
	}
	if ((check_func_name("generic_writepages")) && strstr(pointer, "mapping->a_ops->writepage")) {
		struct address_space *mapping = (struct address_space *)opt;
		if (mapping->a_ops->writepage)
			sprintf(func, FUNCTION_PRINT_FORMAT, mapping->a_ops->writepage);
		return ret;
	}
#ifdef TK5
	if ((check_func_name("read_pages")) && strstr(pointer, "aops->read_folio")) {
		struct readahead_control *rac = (struct readahead_control *)opt;
		struct address_space_operations *a_ops = rac->mapping->a_ops;
		if (a_ops && a_ops->read_folio)
			sprintf(func, FUNCTION_PRINT_FORMAT, a_ops->read_folio);
		return ret;
	}
	if ((check_func_name("read_pages")) && strstr(pointer, "aops->readahead")) {
		struct readahead_control *rac = (struct readahead_control *)opt;
		struct address_space_operations *a_ops = rac->mapping->a_ops;
		if (a_ops && a_ops->readahead)
			sprintf(func, FUNCTION_PRINT_FORMAT, a_ops->readahead);
		return ret;
	}
#else
	if ((check_func_name("generic_file_buffered_read")) && strstr(pointer, "mapping->a_ops->readpage")) {
		struct kiocb *iocb = (struct kiocb *)opt;
		struct file *filp = iocb->ki_filp;
		struct address_space *mapping = filp->f_mapping;
		if (mapping->a_ops->readpage)
			sprintf(func, FUNCTION_PRINT_FORMAT, mapping->a_ops->readpage);
		return ret;
	}
	if ((check_func_name("generic_file_buffered_read")) && strstr(pointer, "mapping->a_ops->is_partially_uptodate")) {
		struct kiocb *iocb = (struct kiocb *)opt;
		struct file *filp = iocb->ki_filp;
		struct address_space *mapping = filp->f_mapping;
		if (mapping->a_ops->is_partially_uptodate)
			sprintf(func, FUNCTION_PRINT_FORMAT, mapping->a_ops->is_partially_uptodate);
		return ret;
	}
	if ((check_func_name("generic_file_buffered_read")) && strstr(pointer, "mapping->a_ops->readpages")) {
		struct address_space *mapping = (struct address_space *)opt;
		if (mapping->a_ops->readpages)
			sprintf(func, FUNCTION_PRINT_FORMAT, mapping->a_ops->readpages);
		return ret;
	}
#endif
	if ((check_func_name("truncate_error_page")) && strstr(pointer, "mapping->a_ops->error_remove_page")) {
		struct address_space * mapping = (struct address_space *)opt3;
		if (mapping->a_ops->error_remove_page)
			sprintf(func, FUNCTION_PRINT_FORMAT, mapping->a_ops->error_remove_page);
		return ret;
	}

	/***************** scheduler *****************/
	// check `pick_next_task` and `__pick_next_task`
	if (check_func_name("pick_next_task") && strstr(pointer, "fair_sched_class.pick_next_task")) {
		sprintf(func, "%s", "pick_next_task_fair");
		return ret;
	}
	if (check_func_name("select_task_rq") && strstr(pointer, "p->sched_class->select_task_rq")) {
		struct task_struct *p = (struct task_struct *)opt;
		sprintf(func, FUNCTION_PRINT_FORMAT, p->sched_class->select_task_rq);
		return ret;
	}
	if (check_func_name("enqueue_task") && strstr(pointer, "p->sched_class->enqueue_task")) {
		struct task_struct *p = (struct task_struct *)opt2;
		sprintf(func, FUNCTION_PRINT_FORMAT, p->sched_class->enqueue_task);
		return ret;
	}
	if (check_func_name("dequeue_task") && strstr(pointer, "p->sched_class->dequeue_task")) {
		struct task_struct *p = (struct task_struct *)opt2;
		sprintf(func, FUNCTION_PRINT_FORMAT, p->sched_class->dequeue_task);
		return ret;
	}
	if (check_func_name("do_sched_yield") && strstr(pointer, "current->sched_class->yield_task")) {
		sprintf(func, FUNCTION_PRINT_FORMAT, current->sched_class->yield_task);
		return ret;
	}
	if (check_func_name("yield_to") && strstr(pointer, "curr->sched_class->yield_to_task")) {
		sprintf(func, FUNCTION_PRINT_FORMAT, current->sched_class->yield_to_task);
		return ret;
	}
	if (check_func_name("put_prev_task") && strstr(pointer, "prev->sched_class->put_prev_task")) {
		struct task_struct *prev = (struct task_struct *)opt2;
		sprintf(func, FUNCTION_PRINT_FORMAT, prev->sched_class->put_prev_task);
		return ret;
	}
	if (check_func_name("do_set_cpus_allowed") && strstr(pointer, "p->sched_class->set_cpus_allowed")) {
		struct task_struct *p = (struct task_struct *)opt;
		sprintf(func, FUNCTION_PRINT_FORMAT, p->sched_class->set_cpus_allowed);
		return ret;
	}
	if (check_func_name("task_sched_runtime") && strstr(pointer, "p->sched_class->update_curr")) {
		struct task_struct *p = (struct task_struct *)opt;
		sprintf(func, FUNCTION_PRINT_FORMAT, p->sched_class->update_curr);
		return ret;
	}

	/***************** network *****************/
	if (check_func_name("__sock_release") && strstr(pointer, "sock->ops->release")) {
		struct socket *sock = (struct socket *)opt;
		if (sock->ops)
			sprintf(func, FUNCTION_PRINT_FORMAT, sock->ops->release);
		return ret;
	}
	if ((check_func_name("kernel_bind") || check_func_name("bind_mcastif_addr")) && strstr(pointer, "sock->ops->bind")) {
		struct socket *sock = (struct socket *)opt;
		if (sock->ops)
			sprintf(func, FUNCTION_PRINT_FORMAT, sock->ops->bind);
		return ret;
	}
	if (check_func_name("kernel_bind") && strstr(pointer, "sock->ops->bind")) {
		struct socket *sock = (struct socket *)opt;
		if (sock->ops)
			sprintf(func, FUNCTION_PRINT_FORMAT, sock->ops->bind);
		return ret;
	}
	if (check_func_name("make_send_sock") && strstr(pointer, "sock->ops->connect")) {
		struct socket *sock = (struct socket *)opt;
		if (sock->ops)
			sprintf(func, FUNCTION_PRINT_FORMAT, sock->ops->bind);
		return ret;
	}
	if (check_func_name("sock_poll") && strstr(pointer, "sock->ops->poll")) {
		struct file *file = (struct file *)opt;
		struct socket *sock = file->private_data;
		if (sock->ops)
			sprintf(func, FUNCTION_PRINT_FORMAT, sock->ops->poll);
		return ret;
	}
#if 0
	if (check_func_name("rfkill_poll") && strstr(pointer, "rfkill->ops->poll")) {
		struct work_struct *work = (struct work_struct *)opt;
		struct rfkill *rfkill = container_of(work, struct rfkill, poll_work.work);
		if (rfkill && rfkill->ops)
			sprintf(func, FUNCTION_PRINT_FORMAT, rfkill->ops->poll);
		return ret;
	}
#endif
	if (check_func_name("sock_do_ioctl") && strstr(pointer, "sock->ops->ioctl")) {
		struct socket *sock = (struct socket *)opt;
		sprintf(func, FUNCTION_PRINT_FORMAT, sock->ops->ioctl);
		return ret;
	}
#ifndef TK3
	if (check_func_name("sock_ioctl") && strstr(pointer, "sock->ops->gettstamp")) {
		struct file *file = (struct file *)opt;
		struct socket *sock = file->private_data;
		sprintf(func, FUNCTION_PRINT_FORMAT, sock->ops->gettstamp);
		return ret;
	}
	if (check_func_name("compat_sock_ioctl_trans") && strstr(pointer, "sock->ops->gettstamp")) {
		struct socket *sock = (struct socket *)opt2;
		if (sock->ops->gettstamp)
			sprintf(func, FUNCTION_PRINT_FORMAT, sock->ops->gettstamp);
		return ret;
	}
#endif
	if (check_func_name("kernel_listen") && strstr(pointer, "sock->ops->listen")) {
		struct socket *sock = (struct socket *)opt;
		if (sock->ops->listen)
			sprintf(func, FUNCTION_PRINT_FORMAT, sock->ops->listen);
		return ret;
	}
	if ((check_func_name("sock_sendmsg_nosec") || check_func_name("sock_sendmsg"))&& strstr(pointer, "INDIRECT_CALL_INET")) {
		struct socket *sock = (struct socket *)opt;
		if (sock->ops->sendmsg)
			sprintf(func, FUNCTION_PRINT_FORMAT, sock->ops->sendmsg);
		return ret;
	}
	if ((check_func_name("sock_recvmsg_nosec") || check_func_name("sock_recvmsg")) && strstr(pointer, "INDIRECT_CALL_INET")) {
		struct socket *sock = (struct socket *)opt;
		if (sock->ops->recvmsg)
			sprintf(func, FUNCTION_PRINT_FORMAT, sock->ops->recvmsg);
		return ret;
	}
	if (check_func_name("sock_mmap") && strstr(pointer, "sock->ops->mmap")) {
		struct file *file = (struct file *)opt;
		struct socket *sock = file->private_data;
		if (sock->ops->recvmsg)
			sprintf(func, FUNCTION_PRINT_FORMAT, sock->ops->recvmsg);
		return ret;
	}
	if (check_func_name("sock_splice_read") && strstr(pointer, "sock->ops->splice_read")) {
		struct socket *sock = (struct socket *)opt;
		if (sock->ops->splice_read)
			sprintf(func, FUNCTION_PRINT_FORMAT, sock->ops->splice_read);
		return ret;
	}
	if (check_func_name("kernel_sendmsg_locked") && strstr(pointer, "sock->ops->sendmsg_locked")) {
		struct socket *sock = (struct socket *)opt;
		if (sock->ops->sendmsg_locked)
			sprintf(func, FUNCTION_PRINT_FORMAT, sock->ops->sendmsg_locked);
		return ret;
	}
#ifndef TK3
	if (check_func_name("sock_setsockopt") && strstr(pointer, "sock->ops->set_rcvlowat")) {
		struct socket *sock = (struct socket *)opt;
		if (sock->ops->set_rcvlowat)
			sprintf(func, FUNCTION_PRINT_FORMAT, sock->ops->set_rcvlowat);
		return ret;
	}
	if (check_func_name("sock_setsockopt") && strstr(pointer, "sock->ops->set_rcvlowat")) {
		struct socket *sock = (struct socket *)opt;
		if (sock->ops->set_rcvlowat)
			sprintf(func, FUNCTION_PRINT_FORMAT, sock->ops->set_rcvlowat);
		return ret;
	}
	if (check_func_name("__inet_stream_connect") && strstr(pointer, "sk->sk_prot->pre_connect")) {
		struct socket *sock = (struct socket *)opt;
		struct sock *sk = sock->sk;
		if (sk->sk_prot->pre_connect)
			sprintf(func, FUNCTION_PRINT_FORMAT, sk->sk_prot->pre_connect);
		return ret;
	}
#endif
	if ((check_func_name("inet_sendmsg") || check_func_name("inet6_sendmsg")) && strstr(pointer, "INDIRECT_CALL_2")) {
		struct socket *sock = (struct socket *)opt;
		struct sock *sk = sock->sk;
		if (sk->sk_prot->sendmsg)
			sprintf(func, FUNCTION_PRINT_FORMAT, sk->sk_prot->sendmsg);
		return ret;
	}
	// check `inet_stream_connect` and `__inet_stream_connect`
	if ((check_func_name("pn_socket_connect") || check_func_name("inet_stream_connect")
			|| check_func_name("ieee802154_sock_connect"))
			&& strstr(pointer, "sk->sk_prot->connect")) {
		struct socket *sock = (struct socket *)opt;
		struct sock *sk = sock->sk;
		if (sk->sk_prot->connect)
			sprintf(func, FUNCTION_PRINT_FORMAT, sk->sk_prot->connect);
		return ret;
	}
	// check `inet_stream_connect` and `__inet_stream_connect`
	if ((check_func_name("inet_stream_connect") || check_func_name("inet_shutdown")
			|| check_func_name("ieee802154_sock_connect"))
			&& strstr(pointer, "sk->sk_prot->disconnect")) {
		struct socket *sock = (struct socket *)opt;
		struct sock *sk = sock->sk;
		if (sk->sk_prot->disconnect)
			sprintf(func, FUNCTION_PRINT_FORMAT, sk->sk_prot->disconnect);
		return ret;
	}
	if (check_func_name("pn_socket_ioctl") && strstr(pointer, "sk->sk_prot->accept")) {
		struct socket *sock = (struct socket *)opt;
		struct sock *sk = sock->sk;
		if (sk->sk_prot->accept)
			sprintf(func, FUNCTION_PRINT_FORMAT, sk->sk_prot->accept);
		return ret;
	}
	if ((check_func_name("pn_socket_ioctl") || check_func_name("inet6_ioctl")
			|| check_func_name("inet_ioctl") || check_func_name("ieee802151_sock_ioctl"))
			&& strstr(pointer, "sk->sk_prot->ioctl")) {
		struct socket *sock = (struct socket *)opt;
		struct sock *sk = sock->sk;
		if (sk->sk_prot->ioctl)
			sprintf(func, FUNCTION_PRINT_FORMAT, sk->sk_prot->ioctl);
		return ret;
	}
	if (check_func_name("compat_sock_common_setsockopt") && strstr(pointer, "sk->sk_prot->setsockopt")) {
		struct socket *sock = (struct socket *)opt;
		struct sock *sk = sock->sk;
		if (sk->sk_prot->setsockopt)
			sprintf(func, FUNCTION_PRINT_FORMAT, sk->sk_prot->setsockopt);
		return ret;
	}
	if (check_func_name("compat_sock_common_getsockopt") && strstr(pointer, "sk->sk_prot->getsockopt")) {
		struct socket *sock = (struct socket *)opt;
		struct sock *sk = sock->sk;
		if (sk->sk_prot->getsockopt)
			sprintf(func, FUNCTION_PRINT_FORMAT, sk->sk_prot->getsockopt);
		return ret;
	}
	if (check_func_name("sock_setsockopt") && strstr(pointer, "sk->sk_prot->keepalive")) {
		struct socket *sock = (struct socket *)opt;
		struct sock *sk = sock->sk;
		if (sk->sk_prot->keepalive)
			sprintf(func, FUNCTION_PRINT_FORMAT, sk->sk_prot->keepalive);
		return ret;
	}
	if (check_func_name("sock_common_recvmsg") && strstr(pointer, "sk->sk_prot->recvmsg")) {
		struct socket *sock = (struct socket *)opt;
		struct sock *sk = sock->sk;
		if (sk->sk_prot->recvmsg)
			sprintf(func, FUNCTION_PRINT_FORMAT, sk->sk_prot->recvmsg);
		return ret;
	}
	// check `sk_backlog_rcv` and `__sk_backlog_rcv`
	if (check_func_name("sk_backlog_rcv") && strstr(pointer, "sk->sk_backlog_rcv")) {
		struct sock *sk = (struct sock *)opt;
		if (sk->sk_backlog_rcv)
			sprintf(func, FUNCTION_PRINT_FORMAT, sk->sk_backlog_rcv);
		return ret;
	}
	if (check_func_name("release_sock") && strstr(pointer, "sk->sk_prot->release_cb")) {
		struct sock *sk = (struct sock *)opt;
		if (sk->sk_prot->release_cb)
			sprintf(func, FUNCTION_PRINT_FORMAT, sk->sk_prot->release_cb);
		return ret;
	}
	// check `inet6_bind` and `__inet6_bind`
	// check `inet_bind` and `__inet_bind`
	if ((check_func_name("pn_socket_bind") || check_func_name("inet6_bind")
			|| check_func_name("inet_csk_listen_start") || check_func_name("inet_bind")
			|| check_func_name("inet_autobind"))
			&& strstr(pointer, "sk->sk_prot->get_port")) {
		struct sock *sk = (struct sock *)opt;
		if (sk->sk_prot->get_port)
			sprintf(func, FUNCTION_PRINT_FORMAT, sk->sk_prot->release_cb);
		return ret;
	}
#ifdef TK4_NEW_1
	// check `inet6_bind` and `__inet6_bind`
	if (check_func_name("inet6_bind") && strstr(pointer, "sk->sk_prot->put_port")) {
		struct sock *sk = (struct sock *)opt;
		if (sk->sk_prot->put_port)
			sprintf(func, FUNCTION_PRINT_FORMAT, sk->sk_prot->put_port);
		return ret;
	}
	// check `inet_bind` and `__inet_bind`
	if ((check_func_name("inet_autobind") || check_func_name("inet_bind")) && strstr(pointer, "sk->sk_prot->put_port")) {
		struct sock *sk = (struct sock *)opt;
		if (sk->sk_prot->put_port)
			sprintf(func, FUNCTION_PRINT_FORMAT, sk->sk_prot->put_port);
		return ret;
	}
#endif
	if ((check_func_name("sk_enter_memory_pressure") || check_func_name("sk_stream_alloc_skb")
			|| check_func_name("tls_do_allocation")) && strstr(pointer, "sk->sk_prot->enter_memory_pressure")) {
		struct sock *sk = (struct sock *)opt;
		if (sk->sk_prot->enter_memory_pressure)
			sprintf(func, FUNCTION_PRINT_FORMAT, sk->sk_prot->enter_memory_pressure);
		return ret;
	}
	if (check_func_name("sk_leave_memory_pressure") && strstr(pointer, "sk->sk_prot->leave_memory_pressure")) {
		struct sock *sk = (struct sock *)opt;
		if (sk->sk_prot->leave_memory_pressure)
			sprintf(func, FUNCTION_PRINT_FORMAT, sk->sk_prot->leave_memory_pressure);
		return ret;
	}
	// check `sk_stream_memory_free` and `__sk_stream_memory_free`
	if (check_func_name("sk_stream_memory_free") && strstr(pointer, "sk->sk_prot->stream_memory_free")) {
		struct sock *sk = (struct sock *)opt;
		if (sk->sk_prot->stream_memory_free)
			sprintf(func, FUNCTION_PRINT_FORMAT, sk->sk_prot->stream_memory_free);
		return ret;
	}
	if ((check_func_name("inet_recvmsg") || check_func_name("inet_sendmsg")
			|| check_func_name("inet6_recvmsg") || check_func_name("inet6_sendmsg"))
			&& strstr(pointer, "INDIRECT_CALL_2")) {
		struct socket *sock = (struct socket *)opt;
		struct sock *sk = sock->sk;
		if (sk->sk_prot->recvmsg)
			sprintf(func, FUNCTION_PRINT_FORMAT, sk->sk_prot->recvmsg);
		return ret;
	}
#ifndef TK5
	if (check_func_name("generic_make_request")) {
		struct bio *bio = (struct bio *)opt;
		struct request_queue *q;
		if (bio && bio->bi_disk)
			q= bio->bi_disk->queue;
		if (q && q->make_request_fn)
			sprintf(func, FUNCTION_PRINT_FORMAT, q->make_request_fn);
		return ret;
	}
#endif
	return false;
}
